package org.proteored.miapeapi.xml.mzidentml.adapter;

import java.util.List;
import java.util.Set;

import javax.xml.datatype.DatatypeConfigurationException;

import org.apache.log4j.Logger;
import org.proteored.miapeapi.cv.ControlVocabularyManager;
import org.proteored.miapeapi.cv.PSIMassSpectrometryOntology;
import org.proteored.miapeapi.cv.ms.ContactPositionMS;
import org.proteored.miapeapi.interfaces.Adapter;
import org.proteored.miapeapi.interfaces.Software;
import org.proteored.miapeapi.interfaces.ms.MSContact;
import org.proteored.miapeapi.interfaces.msi.IdentifiedProteinSet;
import org.proteored.miapeapi.interfaces.msi.MiapeMSIDocument;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.AnalysisDataType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.AnalysisProtocolCollectionType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.AnalysisSoftwareListType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.CvListType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.DataCollectionType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECollectionAuditCollectionType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECollectionProviderType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECommonAuditContactRoleType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECommonAuditContactRoleType.Role;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECommonAuditOrganizationType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECommonAuditPersonType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.FuGECommonOntologyCvType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.MzIdentML;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.ObjectFactory;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchAnalysisSoftwareType;
import org.proteored.miapeapi.xml.mzidentml.autogenerated.PSIPIAnalysisSearchSpectrumIdentificationProtocolType;
import org.proteored.miapeapi.xml.mzidentml.util.MzidentmlControlVocabularyXmlFactory;
import org.proteored.miapeapi.xml.mzidentml.util.Utils;

/**
 * Implementation of {@link MzIdentML} from a {@link MiapeMSIDocument} object.
 * 
 * @author Salva
 * 
 */
public class MzIdentmlXMLAdapter implements Adapter<MzIdentML> {
	private final MiapeMSIDocument miapeMSI;
	private final MzidentmlControlVocabularyXmlFactory cvFactory;
	private final ObjectFactory factory;
	private static Logger log = Logger.getLogger("log4j.logger.org.proteored");

	public MzIdentmlXMLAdapter(MiapeMSIDocument miapeMSI,
			ControlVocabularyManager controlVocabularyUtil) {
		log.info("MzIdentmlXMLAdapter");
		this.factory = new ObjectFactory();
		this.cvFactory = new MzidentmlControlVocabularyXmlFactory(factory, controlVocabularyUtil);
		this.miapeMSI = miapeMSI;
	}

	@Override
	public MzIdentML adapt() {
		MzIdentML mzIdentML = factory.createMzIdentML();

		// Add mzIdentML data
		addMzIdentMLData(mzIdentML);

		// cvList
		CvListType cvList = factory.createCvListType();
		FuGECommonOntologyCvType cv = factory.createFuGECommonOntologyCvType();
		cv.setFullName(PSIMassSpectrometryOntology.getFullName());
		cv.setURI(PSIMassSpectrometryOntology.getAddress());
		cv.setVersion(PSIMassSpectrometryOntology.getVersion());
		cvList.getCv().add(cv);
		mzIdentML.setCvList(cvList);

		// forech protein set:
		if (miapeMSI.getIdentifiedProteinSets() != null) {
			for (IdentifiedProteinSet proteinSet : miapeMSI.getIdentifiedProteinSets()) {
				// create an SpectrumIdentificationProtocol
				AnalysisProtocolCollectionType analysisProtocolCollection = factory
						.createAnalysisProtocolCollectionType();
				PSIPIAnalysisSearchSpectrumIdentificationProtocolType spectrumIdentificationProtocol = new PSIPIAnalysisSearchSpectrumIdentificationProtocolTypeAdapter(
						proteinSet, factory).adapt();

				analysisProtocolCollection.getSpectrumIdentificationProtocol().add(
						spectrumIdentificationProtocol);
				mzIdentML.setAnalysisProtocolCollection(analysisProtocolCollection);
			}
		}

		// ********************************************************************************
		// create AnalysisSoftwareListType
		AnalysisSoftwareListType analysisSoftwareList = factory.createAnalysisSoftwareListType();
		mzIdentML.setAnalysisSoftwareList(analysisSoftwareList);

		// create FuGECollectionAuditCollectionType
		FuGECollectionAuditCollectionType auditCollection = factory
				.createFuGECollectionAuditCollectionType();
		mzIdentML.setAuditCollection(auditCollection);

		// create FuGECollectionProviderType
		FuGECollectionProviderType provider = factory.createFuGECollectionProviderType();
		mzIdentML.setProvider(provider);

		// create DataCollection
		DataCollectionType dataCollection = factory.createDataCollectionType();
		mzIdentML.setDataCollection(dataCollection);

		// ********************************************************************************

		// Add AnalysisSoftwareList from MIAPE_MSI_Software
		addAnalysisSoftwareList(mzIdentML);

		// Add Provider information from the contact of the MIAPE
		addProvider(mzIdentML);

		// Add Sequence information from the database section
		addDataCollection(mzIdentML);

		return mzIdentML;
	}

	private void addMzIdentMLData(MzIdentML mzIdentML) {
		// creation date
		try {
			mzIdentML.setCreationDate(miapeMSI.getDate().toXMLGregorianCalendar());
		} catch (DatatypeConfigurationException e) {
			// do nothing
		}
		mzIdentML.setName(miapeMSI.getName());
		mzIdentML.setId(Utils.getIdFromString(miapeMSI.getName()));
		mzIdentML.setVersion(miapeMSI.getVersion());

	}

	private void addDataCollection(MzIdentML mzIdentML) {

		// Inputs
		mzIdentML.getDataCollection().setInputs(
				new InputsTypeAdapter(miapeMSI, factory, cvFactory).adapt());

		// AnalysisData
		AnalysisDataType analysisDataXML = factory.createAnalysisDataType();

		mzIdentML.getDataCollection().setAnalysisData(analysisDataXML);

	}

	private void addProvider(MzIdentML mzIdentML) {
		MSContact contact = miapeMSI.getContact();
		if (contact != null) {

			// add person to auditcollection
			FuGECommonAuditPersonType person = factory.createFuGECommonAuditPersonType();
			person.setAddress(contact.getAddress());
			person.setEmail(contact.getEmail());
			person.setFax(contact.getFax());
			person.setFirstName(contact.getName());
			person.setId(Utils.getIdFromString(contact.getName()));
			person.setLastName(contact.getLastName());
			person.setPhone(contact.getTelephone());
			mzIdentML.getAuditCollection().getContactGroup().add(person);

			// add provider information and reference to the person
			mzIdentML.getProvider().setId(Utils.getIdFromString(contact.getName()));
			mzIdentML.getProvider().setName(contact.getName());
			FuGECommonAuditContactRoleType contactRole = factory
					.createFuGECommonAuditContactRoleType();
			contactRole.setContactRef(person.getId());
			String position = contact.getPosition();
			if (position != null) {
				Role role = factory.createFuGECommonAuditContactRoleTypeRole();
				role.setCvParam(cvFactory.createOntologyCvParamType(position, null,
						ContactPositionMS.getInstance(cvFactory.getCvManager())));
				contactRole.setRole(role);
			}
			mzIdentML.getProvider().setContactRole(contactRole);
		}
	}

	/**
	 * Create a software from msiSoftware section and from validation software
	 * section
	 * 
	 * @param mzIdentML
	 */
	private void addAnalysisSoftwareList(MzIdentML mzIdentML) {
		if (miapeMSI.getSoftwares() != null) {
			addSoftwareList(mzIdentML.getAnalysisSoftwareList().getAnalysisSoftware(),
					miapeMSI.getSoftwares());

			// For each software, create a Organization in Auditcollection for
			// the manufacturer
			for (PSIPIAnalysisSearchAnalysisSoftwareType softwareXML : mzIdentML
					.getAnalysisSoftwareList().getAnalysisSoftware()) {
				if (softwareXML.getContactRole() != null) {
					FuGECommonAuditOrganizationType organization = factory
							.createFuGECommonAuditOrganizationType();
					organization.setId(softwareXML.getContactRole().getContactRef());
					organization.setName(softwareXML.getContactRole().getContactRef());
					mzIdentML.getAuditCollection().getContactGroup().add(organization);
				}
			}
		}
	}

	/**
	 * For each software item in msiSoftwares section (MIAPE MSI), create a new
	 * analysisSoftware in the list
	 * 
	 * @param analysisSoftwareList
	 * @param msiSoftwares
	 */
	private void addSoftwareList(
			List<PSIPIAnalysisSearchAnalysisSoftwareType> analysisSoftwareList,
			Set<Software> msiSoftwares) {
		for (Software software : msiSoftwares) {
			analysisSoftwareList.add(new PSIPIAnalysisSearchAnalysisSoftwareTypeAdapter(software,
					factory, cvFactory).adapt());
		}

	}

}
